package structure;

import java.util.ArrayList;

import algorithm.algorithm;
import algorithm.miscellaneous;

/*
 * crea le big production e calcola i lookahead e crea le connessioni tra di esse
 */

public class bigProdConnection {
	
	private ArrayList<bigProduction> bigProductions;
	private ArrayList<int[]> e_connection;//deve essere di dimensione 4. 0 e 1 indicano bigProduction e item in essa di partenza
								//2 e 3 indicano bigProduction e item in essa di arrivo
	private ArrayList<ArrayList<item>> map;
	private enumerateGrammar e;
	private ArrayList<state> powerset;
	private ArrayList<ArrayList<item>> map_powerset;
	private ArrayList<int[]> connection_powerset;//dimensione 3. stato di partenza [0],
												//indice dell'outgoing[1] stato di arrivo[2]
	private ArrayList<ArrayList<String>> parsingTable;
	private String error;
	
	public bigProdConnection(){
		
		this.bigProductions= new ArrayList<bigProduction>();
		this.e_connection= new ArrayList<int[]>();
		this.e= new enumerateGrammar();
		this.map= new ArrayList<ArrayList<item>>();
		this.powerset= new ArrayList<state>();
		this.map_powerset= new ArrayList<ArrayList<item>>();
		this.connection_powerset= new ArrayList<int[]>();
		this.parsingTable= new ArrayList<ArrayList<String>>();
		this.error= "";
	}
	
	public bigProdConnection(enumerateGrammar e){
		
		this.bigProductions= new ArrayList<bigProduction>();
		this.e_connection= new ArrayList<int[]>();
		this.e= e;
		
		//creo le big production
		for(production p : e.getEnumeratedGrammarIPF()){
			
			bigProduction tmp_big= new bigProduction(p);
			this.bigProductions.add(tmp_big);
		}
		
		this.map= new ArrayList<ArrayList<item>>();
		this.powerset= new ArrayList<state>();
		this.map_powerset= new ArrayList<ArrayList<item>>();
		this.connection_powerset= new ArrayList<int[]>();
		this.parsingTable= new ArrayList<ArrayList<String>>();
		this.error= "";
	}
	
	
	public void createLookahead(){
		//scorro le big production, se trovo che una big production ha gia lookahead allora devo
		//duplicarla e associare il lookahead alla nuova big production
		boolean stop= false;

		int index_stop= this.bigProductions.size();
		int index_for_stop= 0;	
		//questo loop riesegue il controllo sulle big production
		while(!stop){		
			//System.out.println("inizio il while, index_stop= " + index_stop + ", index_for_stop= " + index_for_stop);
			
			ArrayList<bigProduction> ar_bigP= new ArrayList<bigProduction>();
			
			int old_size= this.bigProductions.size();
			for(int index=0;index<old_size; index++){

				bigProduction big= this.bigProductions.get(index);

				//se è l'assioma il lookahead è $
				if(big.getLeftside().equals(e.getAxiom())){
					
					if(!big.hasLookahead()){
						ArrayList<String> lookahead= new ArrayList<String>();
						lookahead.add("$");
						big.setLookahead(lookahead);
					}
				}
				
				{
					//prendo ogni item della big production
					for(item i : big.getItems()){
						
						//prendo il simbolo dopo il punto
						String afterDot= i.getAfterDot();
						//se è un non terminale
						if(e.getVN().contains(afterDot)){
							//prendo il simbolo dopo afterdot, e cioè beta
							String beta= this.getBeta(i);
							if(beta != null){
								i.setCreator();
								//prendo tutte le big production con quel non terminale nel leftside
								ArrayList<bigProduction> bigP= this.getBigProductionByLeftside(afterDot);
								
								//creo il lookahead
								ArrayList<String> tmp_lookahead= new ArrayList<String>();
								tmp_lookahead= this.createSingleLookahead(i);
								
								if(tmp_lookahead != null && !tmp_lookahead.isEmpty()){
									
									for(bigProduction tmp_big : bigP){
										
										if(tmp_big.hasLookahead()){
											bigProduction tmp_big_2= this.duplicateBigProdutcion(tmp_big);
											tmp_big_2.setLookahead(tmp_lookahead);
											ar_bigP.add(tmp_big_2);
										}
										else{

											tmp_big.setLookahead(tmp_lookahead);
										}
									}
								}
							}
						}
					}
				}
			}
			
			this.addAllBigProductions(ar_bigP);
			//controllo sulle bigProduction doppie
			this.removeDoubleBigProduction();
			int new_size= this.bigProductions.size();
			index_for_stop++;
			//se ho fatto delle aggiunte ripeto il ciclo
			if(old_size == new_size && everyoneWithLookahead()){
				
				stop= true;
			}
		}
	}
	
	private ArrayList<String> createSingleLookahead(item item){
		
		ArrayList<String> toReturn= null;
		
		if(!item.isComplete()){
			
			toReturn= new ArrayList<String>();
			
			String afterDot= item.getAfterDot();
			
			if(e.getVN().contains(afterDot)){
				
				//item.printItAll();
				//System.out.println("");
				String beta= this.getBeta(item);
				//System.out.println("beta= "+beta);
				
				if(beta != null){
					
					if(beta.equals("e")){
	
						//toReturn= item.getLookahead();
						toReturn.addAll(item.getLookahead());
					}
					else if(e.getNullable() != null && e.getNullable().contains(beta)){
						
						//toReturn= item.getLookahead();
						toReturn.addAll(item.getLookahead());
						ArrayList<String> tmp= algorithm.First1(e, beta, null, null);
						if(!tmp.isEmpty()){
	
							toReturn.addAll(tmp);
							//System.out.println("aggiungo la first, beta= " + beta);
						}
					}
					else{
	
						ArrayList<String> tmp= algorithm.First1(e, beta, null, null);
						if(!tmp.isEmpty()){
	
							toReturn.addAll(tmp);
							//System.out.println("imposto la first, beta= " + beta);
						}
					}
				}
			}
		}
		
		return toReturn;
	}

	public void createMap(){
		
		for(int i=0; i<this.bigProductions.size(); i++){
			
			bigProduction big= this.bigProductions.get(i);
			big.setIndex(i);
			ArrayList<item> items= new ArrayList<item>();
			for(int j=0; j<big.getItems().size(); j++){
				
				item item= big.getItem(j);
				item.setIndex(j);
				item.setIndexBigProduction(i);
				items.add(item);
			}
			this.map.add(items);
		}
	}

	public void connect(){
		//non prendo gli archi che tornano nella stessa big production
		
		//scorro le bigproduction
		for(int i=0; i<this.bigProductions.size(); i++){
			
			bigProduction big= this.getBigProduction(i);
			
			//scorro gli item
			for(int j=0; j<big.getItems().size(); j++){
				
				item item= big.getItem(j);
				
				if(!item.isComplete()){

					ArrayList<String> lookahead= this.createSingleLookahead(item);
					
					ArrayList<item> items= this.getItemsByLeftside(item.getAfterDot());
					
					for(item it : items){
						
						if(it.isFirst() && lookahead != null 
								&& it.sameLookahead(lookahead)){
							
							int bigProdSend= item.getIndexBigProduction();
							int itemSend= item.getIndex();
							int bigProdReceive= it.getIndexBigProduction();
							int itemReceive= it.getIndex();
							
							if(item.isCreator()){
								
								int[] connect= new int[4];
								connect[0]= bigProdSend;
								connect[1]= itemSend;
								connect[2]= bigProdReceive;
								connect[3]= itemReceive;
								
								this.e_connection.add(connect);
							}
						}
					}
				}
			}
		}
		//rimuovo gli archi che rientrano nell'item
		ArrayList<int[]> toRemove= new ArrayList<int[]>();
		for(int i=0;i<this.e_connection.size();i++){
			
			int[] ar_i= this.e_connection.get(i);
			item sender= this.map.get(ar_i[0]).get(ar_i[1]);
			item receiver= this.map.get(ar_i[2]).get(ar_i[3]);
			
			if(sender.sameAs(receiver)) toRemove.add(ar_i);
		}
		
		if(!toRemove.isEmpty()){
			
			for(int[] i : toRemove){
				
				this.e_connection.remove(i);
			}
		}
	}
	
	public void createPowerset(){
		
		//prendo il primo item che sicuro è connesso a qualcosa visto che la grammatica è aumentata
		item item0= this.bigProductions.get(0).getItem(0);
		
		ArrayList<item> connected0= new ArrayList<item>();
		connected0.add(item0);
		connected0.addAll(this.getConnectionFromItem(item0));
		
		state state0= new state(connected0, "q0");
		
		this.powerset.add(state0);
		
		//inizia il ciclo per il calcolo degli altri stati partendo da state0
		boolean stop= false;
		while(!stop){
			
			int old_size= this.powerset.size();
			
			ArrayList<state> toAdd= new ArrayList<state>();
			for(state st : this.powerset){
				
				ArrayList<String> outgoing= st.getOutgoing();
				for(String s : outgoing){
	
					ArrayList<item> tmp_connected= new ArrayList<item>();
					for(item i : st.getItems()){
						
						if(!i.isComplete() && i.getAfterDot().equals(s)){
							
							//calcola il nuovo stato con arco entrante etichettato s
							item tmp_item= new item();
							tmp_item= this.getNextItemInBP(i);
							if(!tmp_connected.contains(tmp_item)) 
								tmp_connected.add(tmp_item);
							miscellaneous.addAllItemOnce(this.getConnectionFromItem(tmp_item), tmp_connected);
						}
					}
					//qui ho finito di creare lo stato con l'arco entrante s
					if(!tmp_connected.isEmpty()){
						
						state tmp_state= new state(tmp_connected, "q");
						toAdd.add(tmp_state);
					}
				}
				//qui ho finito di creare i nuovi stati con gli archi entranti a partire da quelli uscenti
			}
			
			this.powerset.addAll(toAdd);
			
			this.removeDoubleState();
	
			this.renameAllState();
			
			int new_size= this.powerset.size();
			if(old_size == new_size){
				stop= true;
			}
		}
		
		this.createMapPowerset();
		
		this.connectPowerset();
	}

	public void createMapPowerset(){
		
		for(state st : this.powerset){
			
			this.map_powerset.add(st.getItems());
		}
	}
	
	public void connectPowerset(){
		
		for(int i=0; i<this.powerset.size(); i++){
			
			state tmp_state= this.powerset.get(i);
			ArrayList<String> outgoing= tmp_state.getOutgoing();
			
			for(int j=0; j<outgoing.size(); j++){

				String s= outgoing.get(j);
				
				for(item item : tmp_state.getItems()){
					
					if(!item.isComplete() && item.getAfterDot().equals(s)){
						
						item next_item= this.getNextItemInBP(item);
						
						state next_state= this.getStateFromItem(next_item);
						
						int k=0;
						for(k=0; k<this.powerset.size(); k++){
							
							if(this.powerset.get(k).sameAs(next_state)) break;
						}
						
						int[] connection= new int[3];
						connection[0]= i;
						connection[1]= j;
						connection[2]= k;
						
						this.connection_powerset.add(connection);
						
						break;
					}
				}
			}
		}
	}
	
	public void createParsingTable(){
		//la prima riga della prsing table, l'intestazione
		ArrayList<String> parsingTable0= new ArrayList<String>();
		
		parsingTable0.add("");
		parsingTable0.addAll(e.getVT());
		parsingTable0.add("$");
		parsingTable0.addAll(e.getVN());
		if(parsingTable0.contains("e")) parsingTable0.remove("e");

		this.parsingTable.add(parsingTable0);
		//----------------
		
		for(state st : this.powerset){
			
			ArrayList<String> tmp_parsing= new ArrayList<String>();
			for(String p : parsingTable0){
				
				tmp_parsing.add("");
			}
			tmp_parsing.set(0, st.getLabel());
			
			boolean do_it= true;
			
			if(st.containsCompleteItem()){
				
				ArrayList<item> completeItems= st.getCompleteItems();
				
				//accept part
				if(completeItems.size() == 1){
					
					item it= completeItems.get(0);
					//il leftside è l'assioma
					if(it.getLeftside().equals(e.getAxiom())){
						
						ArrayList<String> tmp_look= it.getLookahead();
						//lookahead dimensione 1
						if(tmp_look.size() == 1){
							
							String tmp_single_look= tmp_look.get(0);
							if(tmp_single_look.equals("$")){
								
								int index= miscellaneous.getPositionOfString(parsingTable0, "$");
								if(tmp_parsing.get(index).equals(""))
									tmp_parsing.set(index, "acc");
								else{

									String tmp_s= tmp_parsing.get(index);
									tmp_parsing.set(index, tmp_s + "/" +"acc");
									this.error= "ERROR: conflitto in [" + st.getLabel()+"," + "$" + "]";
								}
								
							}
						}
					}
					//se il leftside non è l'assioma
					else{
						
						for(String lk : it.getLookahead()){
							
							int index= miscellaneous.getPositionOfString(parsingTable0, lk);
							int index_prod= e.getIndexByRightside(it.getRightsideClean());
							if(tmp_parsing.get(index).equals(""))
								tmp_parsing.set(index, "red"+index_prod);
							else{

								String tmp_s= tmp_parsing.get(index);
								tmp_parsing.set(index, tmp_s + "/" +"red"+index_prod);
								this.error= "ERROR: conflitto in [" + st.getLabel()+"," + lk + "]";
							}
						}
					}
				}
				else{
					
					for(item it : completeItems){

						for(String lk : it.getLookahead()){
							
							int index= miscellaneous.getPositionOfString(parsingTable0, lk);
							int index_prod= e.getIndexByRightside(it.getRightsideClean());
							if(tmp_parsing.get(index).equals(""))
								tmp_parsing.set(index, "red"+index_prod);
							else{

								String tmp_s= tmp_parsing.get(index);
								tmp_parsing.set(index, tmp_s + "/" +"red"+index_prod);
								this.error= "ERROR: conflitto in [" + st.getLabel()+"," + lk + "]";
							}
								
						}
					}
				}
				
			}
			
			//else{
				
				for(int k=0; k<st.getOutgoing().size() && do_it; k++){
					
					String arc= st.getOutgoing().get(k);
					int index= miscellaneous.getPositionOfString(parsingTable0, arc);
						
					if(e.getVT().contains(arc) && !arc.equals("")){
						
						String connected_state= this.getConnectedState(st, arc).getLabel();
						if(tmp_parsing.get(index).equals(""))
							tmp_parsing.set(index, "sh-"+connected_state);
						else{
							String tmp_s= tmp_parsing.get(index);
							tmp_parsing.set(index, tmp_s + "/" +"sh-"+connected_state);
							this.error= "ERROR: conflitto in " + "[" + st.getLabel()+"," + arc + "]";
						}
						
					}
					else if(e.getVN().contains(arc) && !arc.equals("")){

						String connected_state= this.getConnectedState(st, arc).getLabel();
						if(tmp_parsing.get(index).equals(""))
							tmp_parsing.set(index, connected_state);
						else{
							String tmp_s= tmp_parsing.get(index);
							tmp_parsing.set(index, tmp_s + "/" +connected_state);
							this.error= "ERROR: conflitto in " + "[" + st.getLabel()+"," + arc + "]";
						}
						
					}
				}
			//}
			
			this.parsingTable.add(tmp_parsing);
		}
		
	}
	
	public boolean everyoneWithLookahead(){
		
		boolean toReturn= true;
		
		for(bigProduction big : this.bigProductions){
			
			if(!big.hasLookahead()){
				
				toReturn= false;
				break;
			}
		}
		
		return toReturn;
	}
	
	public boolean everythingOkInPT(){
		
		if(this.error.isEmpty()){
			return true;
		}
		
		return false;
	}
	
	public ArrayList<item> getItemsByLeftside(String leftside){
		
		ArrayList<item> toReturn= new ArrayList<item>();
		
		for(bigProduction big : this.bigProductions){
			
			for(item i : big.getItems()){
				
				if(i.getLeftside().equals(leftside)){
					
					toReturn.add(i);
				}
			}
		}
		
		return toReturn;
	}
	
	public String getBeta(item i){
		//null se il simbolo dopo il punto è un terminale
		String toReturn= null;
		
		if(!i.isComplete()){
			
			String afterDot= i.getAfterDot();
			//se è un non terminale
			if(this.e.getVN().contains(afterDot)){
				
				int indexAfterDot= i.getIndexAfterDot();
				//se non è l'ultimo carattere
				if(indexAfterDot < i.getRightside().length()-1){
					
					toReturn= new String("");
					toReturn= i.getRightside().substring(indexAfterDot+1, indexAfterDot+2);
				}
				else if(indexAfterDot == i.getRightside().length()-1){
					
					toReturn= "e";
				}
			}
			
		}
		
		return toReturn;
	}
	
	public item getNextItemInBP(item item){
		
		item toReturn= new item();
		
		for(ArrayList<item> ar : this.map){
			
			boolean stop= false;
			for(int i=0; i<ar.size(); i++){
				
				item tmp_item= ar.get(i);
				
				if(tmp_item.sameAs(item) && i+1<ar.size()){
					
					toReturn= ar.get(i+1);
					stop= true;
					break;
				}
			}
			if(stop) break;
		}
		
		return toReturn;
	}
	
	public ArrayList<bigProduction> getBigProductionByLeftside(String leftside){
		
		ArrayList<bigProduction> toReturn= new ArrayList<bigProduction>();
		
		for(bigProduction big : this.bigProductions){
			
			if(leftside.equals(big.getLeftside())){
				
				toReturn.add(big);
			}
		}
		
		return toReturn;
	}
	
	public bigProduction getBigProduction(int i){
		
		return this.bigProductions.get(i);
	}
	
	public ArrayList<bigProduction> getBigProductions(){
		
		return this.bigProductions;
	}
	
	public ArrayList<int[]> getConnection(){
		
		return this.e_connection;
	}
	
	public ArrayList<item> getConnectionFromItem(item i){
				
		ArrayList<item> toReturn= new ArrayList<item>();
		//scorro le connessioni
		for(int[] ar_i : this.e_connection){
			
			item sender= this.map.get(ar_i[0]).get(ar_i[1]);
			//se l'item passato è un sender prendo tutte le connessioni di quell'item
			if(sender.sameAs(i)){
				
				item receiver= this.map.get(ar_i[2]).get(ar_i[3]);
				toReturn.add(receiver);
				
				if(receiver.isCreator()){
					
					toReturn.addAll(this.getConnectionFromItem(receiver));
				}
			}
		}
		
		return toReturn;
	}
	
	public state getStateFromItem(item i){
		
		for(state st : this.powerset){
			
			for(item it : st.getItems()){
				
				if(it.sameAs(i)){
					
					return st;
				}
			}
		}
		
		return null;
	}
	
	public String getOutgoingArc(int indexState, int indexOut){
		
		state tmp_state= this.powerset.get(indexState);
		String toReturn= tmp_state.getOutgoing().get(indexOut);
		return toReturn;
	}
	
	public state getConnectedState(state st, String arc){
		
		state toReturn= new state();
		
		for(int[] ar_i : this.connection_powerset){
			
			state sender= this.powerset.get(ar_i[0]);
			String tmp_arc= this.getOutgoingArc(ar_i[0], ar_i[1]);
			state receiver= this.powerset.get(ar_i[2]);
			if(sender.sameAs(st) && tmp_arc.equals(arc)){
				
				toReturn= receiver;
				System.out.println("sender= " + sender.getLabel() + " -->"+tmp_arc +" "+receiver.getLabel() );
				break;
			}
		}
		
		return toReturn;
	}

	public bigProduction duplicateBigProdutcion(bigProduction big){
		
		bigProduction toReturn= new bigProduction(big);
		toReturn.setDuplicate();
		
		return toReturn;
	}
	
	public void addAllBigProductions(ArrayList<bigProduction> big){
		
		this.bigProductions.addAll(big);
	}
	
	private boolean connectionExist(item sender, item receiver){
		
		for(int[] i : this.e_connection){
			
			item tmp_sender= this.map.get(i[0]).get(i[1]);
			item tmp_receiver= this.map.get(i[2]).get(i[3]);
			
			if(tmp_sender.sameAsWL(sender) && tmp_receiver.sameAsWL(receiver)){
				
				return true;
			}
		}
		
		return false;
	}
	
	private void removeDoubleBigProduction(){
		
		ArrayList<bigProduction> toRemove= new ArrayList<bigProduction>();
		
		for(int i=0;i<this.bigProductions.size();i++){
			
			for(int j=i+1;j<this.bigProductions.size();j++){
				
				if(this.getBigProduction(i).sameAs(this.getBigProduction(j))){
					
					toRemove.add(this.getBigProduction(j));
				}
			}
		}
		//System.out.println(toRemove);
		if(!toRemove.isEmpty()){
			this.bigProductions.removeAll(toRemove);
		}
	}
	
	private void removeDoubleState(){
		
		ArrayList<state> toRemove= new ArrayList<state>();
		
		for(int i=0; i<this.powerset.size(); i++){
			
			for(int j=i+1; j<this.powerset.size(); j++){
				
				state i_st= this.powerset.get(i);
				state j_st= this.powerset.get(j);
				
				if(i_st.sameAs(j_st)){
					
					toRemove.add(j_st);
				}
			}
		}
		
		if(!toRemove.isEmpty()){
			
			this.powerset.removeAll(toRemove);
		}
	}
	
	private void renameAllState(){
		
		int i=0;
		for(state st : this.powerset){
			
			st.setLabel("q"+i);
			i++;
		}
	}
	
	public void parseInputWord(String input){
		
		ArrayList<String> stack= new ArrayList<String>();
		stack.add("q0");
		char[] c_input= input.toCharArray();
		
		ArrayList<String> stack_duplicate= new ArrayList<String>();
		stack_duplicate.addAll(stack);
		
		boolean stop= false;
		int index_input=0;
		boolean accepted= false;
		while(!stop){
			
			int last= stack.size() - 1;
			String stack_head= stack.get(last);
			String input_head= Character.toString(c_input[index_input]);
			String action= this.action(stack_head, input_head);
			System.out.println("ACTION= " + action);
			
			if(action.startsWith("sh")){
				String label= action.substring(3);
				//System.out.println("ACTION= sh label= " + label + " input_head= " + input_head);
				
				this.shift(stack, label, input_head);
				
				if(!input_head.equals("$"))
					index_input++;
				else{
					System.out.println("ERROR: parola in input terminata.");
				}
			}
			else if(action.startsWith("red")){
				String number= action.substring(3);
				int number_of_production= Integer.valueOf(number);
				
				this.red(stack, number_of_production);
			}
			else if(action.equals("acc")){
				accepted= true;
				stop= true;
			}
			
			/*if(index_input == input.length()-1){
				stop= true;
			}*/
			
		}
		
		if(accepted){
			
			System.out.println("La word in input è accettata.");
		}
		else{
			System.out.println("La word in input non è accettata.");
		}
	}
	
	private String action(String label, String input_head){
		
		String toReturn= "";
		ArrayList<String> parsingTable0= this.parsingTable.get(0);
		for(ArrayList<String> ar : this.parsingTable){
			
			String q= ar.get(0);
			if(q.equals(label)){
				
				int index= miscellaneous.getPositionOfString(parsingTable0, input_head);
				
				toReturn= ar.get(index);
			}
		}
		
		return toReturn;
	}
	
	private String goTo(String label, String leftside){
		
		String toReturn="";
		ArrayList<String> parsingTable0= this.parsingTable.get(0);
		for(ArrayList<String> ar : this.parsingTable){
			
			String q= ar.get(0);
			if(q.equals(label)){
				
				int index= miscellaneous.getPositionOfString(parsingTable0, leftside);
				
				toReturn= ar.get(index);
			}
		}
		
		return toReturn;
	}
	
	private void shift(ArrayList<String> stack, String label, String input){
		
		stack.add(input);
		stack.add(label);
	}
	
	private void red(ArrayList<String> stack, int number_of_production){
		
		String leftside=  this.e.getLeftside().get(number_of_production);
		String rightside= this.e.getRightside().get(number_of_production);
		
		int toRemove= rightside.length() * 2;
		int start= stack.size()-1;
		int end= start - toRemove;
		for(int i= start; i>end; i--){
			
			stack.remove(i);
		}
		String label= stack.get(stack.size()-1);
		stack.add(leftside);
		
		String goTo= this.goTo(label, leftside);
		stack.add(goTo);
	}

	public void printItAll(){

		System.out.println("==================BIG PRODUCTIONS==================");
		System.out.println("");
		for(bigProduction big : this.bigProductions){
			
			big.printItAll();
		}
		//System.out.println("BIG PRODUCTIONS END");
		System.out.println("");
	}
	
	public void printMap(){
		
		for(int i=0; i<this.map.size(); i++){
			
			System.out.print(i + ". ");
			
			for(int j=0; j<this.map.get(i).size(); j++){
				
				System.out.print(j + ".");
				this.map.get(i).get(j).printItAll();
				System.out.print("--");
			}
			System.out.println("");
			
		}
	}
	
	public void printConnections(){
		
		for(int[] i : this.e_connection){
			
			System.out.println("["+i[0] + "," + i[1]+"]" + " -->e " + "["+i[2]+"," + i[3]+"]");
		}
	}
	
	public void printPowerset(){
		
		for(state state : this.powerset){
			
			state.printItAll();
		}
	}
	
	public void printMapPowerset(){
		
		for(int i=0; i<this.map_powerset.size(); i++){
			
			System.out.print(i + ". ");
			
			for(int j=0; j<this.map_powerset.get(i).size(); j++){
				
				System.out.print(j + ".");
				this.map_powerset.get(i).get(j).printItAll();
				System.out.print("--");
			}
			System.out.println("");
			
		}
	}
	
	public void printConnectionsPowerset(){
		
		for(int[] i : this.connection_powerset){
			
			System.out.println("["+i[0] + " -->" + this.getOutgoingArc(i[0], i[1]) + " " +i[2] + "]");
		}
	}
	
	public void printParsingTable(){
		
		for(ArrayList<String> ar : this.parsingTable){
			
			System.out.println(ar);
		}
	}
	
	public void printError(){
		
		System.out.println(this.error);
	}

}
